﻿using ComLib.ComType;
using DeviceCommon;
using LogLib;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace CVR100AReader
{
    public class CVRReader : DeviceBase
    {
        /// <summary>
        /// 阅读器连接的串口号（或者USB接口索引）
        /// </summary>
        protected int _port = 0;
        public int Port
        {
            get { return _port; }
        }

        private bool isReading = false;

        private Polling poll = null;

        /// <summary>
        /// 头像照片路径
        /// </summary>
        protected string ZPPath = "";

        /// <summary>
        /// 指纹照片路径
        /// </summary>
        protected string FPPath = "";

        /// <summary>
        /// 阅读器选项
        /// </summary>
        protected IDCReaderOption _option = new IDCReaderOption();
        public IDCReaderOption Option
        {
            get { return _option; }
            set { _option = value; }
        }

        public CVRReader()
        {
            LoadConfig();
        }

        public bool Init()
        {
            _error = "";
            try
            {
                int num = 0;
                int port = 0;
                port = 0x3e9;
                while (true)
                {
                    bool flag2 = port <= 0x3f8;
                    if (flag2)
                    {
                        num = CVRSDK.CVR_InitComm(port);
                        if (num != 1)
                        {
                            port++;
                            continue;
                        }
                        else
                        {
                            _port = port;
                            SavePort();
                            Log.WriteAsync($"身份证阅读器初始化成功，USB口{port}");
                            return true;
                        }                       
                    }
                    else
                    {
                        port = 1;
                        // 设置波特率
                        CVRSDK.CVR_SetComBaudrate(_option.Baudrate);
                        while (true)
                        {
                            flag2 = port <= 0x10;
                            if (!flag2)
                            {
                                break;
                            }
                            num = CVRSDK.CVR_InitComm(port);
                            if (num != 1)
                            {
                                port++;
                                continue;
                            }
                            _port = port;
                            SavePort();
                            Log.WriteAsync($"打开身份证阅读器成功，串口{port}");
                            return true;
                        }
                    }
                    break;
                }
                _error = "打开身份证阅读器失败，请检查阅读器是否连接.";
                Log.WriteAsync(_error);
            }
            catch (Exception ex)
            {
                Log.WriteExceptionAsync(ex.ToString());
                _error = "打开身份证阅读器异常:" + ex.Message;
                Log.WriteAsync(_error);
            }           
            return false;
        }

        public bool Open(int port, int baudrate)
        {
            _port = port;
            try
            {
                bool flag = false;
                Log.WriteAsync($"初始化身份证阅读器，打开串口:{port}, 波特率:{baudrate}");
                // 设置波特率
                CVRSDK.CVR_SetComBaudrate(baudrate);
                int nRet = CVRSDK.CVR_InitComm(_port);
                if (1 == nRet)
                {
                    Log.WriteAsync("打开身份证阅读器成功.");
                    flag = true;
                    SavePort();
                }
                else
                {
                    CVRSDK.CVR_CloseComm();
                    _error = $"身份证阅读器打开串口COM{port}({baudrate})失败，code:{nRet}.";
                    Log.WriteAsync(_error);
                }             
                _bExited = false;
                _bInited = flag;
                return flag;
            }
            catch (Exception exception)
            {
                Log.WriteAsync("打开身份证阅读器异常，Error:" + exception.Message);
            }
            Log.WriteAsync("打开身份证阅读器失败");
            return false;
        }

        public bool Close()
        {
            int num = CVRSDK.CVR_CloseComm();
            Log.WriteAsync(string.Format("关闭身份证阅读器{0}", (num == 1) ? "成功" : "失败"));
            if(num == 1)
            {
                _bInited = false;
                _bExited = true;
                _state = DeviceState.NotInitialized;
                return true;
            }
            else
            {
                return false;
            }
        }

        public bool ReadCard(out IdCardInfo info)
        {
            info = null;
            if (isReading)
            {
                return false;
            }              
            isReading = true;         
            DateTime now = DateTime.Now;
            try
            {
                int count = 0;
                int num = CVRSDK.CVR_Authenticate();
                while(num != 1 && count < 5)
                {
                    Thread.Sleep(600);
                    num = CVRSDK.CVR_Authenticate();                   
                    count++;            
                }        
                if (num != 1)
                {
                    _error = $"寻卡失败, code:{num}";
                    Log.WriteAsync(_error);
                    return false;
                }               
                Log.WriteAsync("卡认证成功");
                count = 0;
                num = CVRSDK.CVR_Read_Content(4);
                while(num != 1 && count < 3)
                {
                    Thread.Sleep(600);
                    num = CVRSDK.CVR_Read_Content(4);
                    count++;
                }
                if (num != 1)
                {
                    _error = $"读卡失败，code:{num}";
                    Log.WriteAsync(_error);
                    return false;
                }
                Log.WriteAsync("开始读卡的详细信息");
                info = FillData();
                Log.WriteAsync(
                    $"姓名:{info.IdCardName}," +
                    $"性别:{info.Sex}," +
                    $"出生日期{info.Birthday}," +
                    $"签发机关:{info.Department}," +
                    $"身份证号:{info.IdCardCode}," +
                    $"民族:{info.Nation}," +
                    $"起始日期:{info.Validate}," +
                    $"有效期限:{info.ExpiryDate}, " +
                    $"头像路径:{info.Photo}");                 
                return true;
            }
            catch (Exception e)
            {
                Log.WriteExceptionAsync(e.ToString());
                info = null;
                _error = $"读身份证异常: {e.Message}";
                Log.WriteAsync(_error);
                return false;
            }
            finally
            {
                isReading = false;
            }           
        }

        private System.Drawing.Image HeadImage = null;

        public IdCardInfo FillData()
        {
            IdCardInfo info = new IdCardInfo();
            try
            {
                info.Photo = ZPPath;
                int length;
                byte[] name = new byte[128];
                length = 128;
                CVRSDK.GetPeopleName(ref name[0], ref length);

                byte[] cnName = new byte[128];
                length = 128;
                CVRSDK.GetPeopleChineseName(ref cnName[0], ref length);

                byte[] number = new byte[128];
                length = 128;
                CVRSDK.GetPeopleIDCode(ref number[0], ref length);

                byte[] peopleNation = new byte[128];
                length = 128;
                CVRSDK.GetPeopleNation(ref peopleNation[0], ref length);

                byte[] peopleNationCode = new byte[128];
                length = 128;
                CVRSDK.GetNationCode(ref peopleNationCode[0], ref length);

                byte[] validtermOfStart = new byte[128];
                length = 128;
                CVRSDK.GetStartDate(ref validtermOfStart[0], ref length);

                byte[] birthday = new byte[128];
                length = 128;
                CVRSDK.GetPeopleBirthday(ref birthday[0], ref length);

                byte[] address = new byte[128];
                length = 128;
                CVRSDK.GetPeopleAddress(ref address[0], ref length);

                byte[] validtermOfEnd = new byte[128];
                length = 128;
                CVRSDK.GetEndDate(ref validtermOfEnd[0], ref length);

                byte[] signdate = new byte[128];
                length = 128;
                CVRSDK.GetDepartment(ref signdate[0], ref length);

                byte[] sex = new byte[128];
                length = 128;
                CVRSDK.GetPeopleSex(ref sex[0], ref length);

                byte[] Uid = new byte[128];
                length = 128;

                CVRSDK.GetIDCardUID(ref Uid[0], 128);

                bool bCivic = true;
                byte[] certType = new byte[32];
                length = 32;
                CVRSDK.GetCertType(ref certType[0], ref length);

                string strType = System.Text.Encoding.ASCII.GetString(certType).Replace("\0", "").Trim();
                int nStart = strType.IndexOf("I");
                if (nStart != -1)
                {
                    bCivic = false;
                }

                // GB2312
                Encoding encode = System.Text.Encoding.GetEncoding(_option.EncodingName);
                if (bCivic)
                {                   
                    info.IdCardName = encode.GetString(name).Replace("\0", "").Trim();
                    info.Sex = encode.GetString(sex).Replace("\0", "").Trim();
                    info.Nation = encode.GetString(peopleNation).Replace("\0", "").Trim();                
                    info.Birthday = encode.GetString(birthday).Replace("\0", "").Trim();
                    info.IdCardCode= encode.GetString(number).Replace("\0", "").Trim();
                    info.Address = encode.GetString(address).Replace("\0", "").Trim();
                    info.Department = encode.GetString(signdate).Replace("\0", "").Trim();
                    info.Validate = encode.GetString(validtermOfStart).Replace("\0", "").Trim();
                    info.ExpiryDate = encode.GetString(validtermOfEnd).Replace("\0", "").Trim();
                    info.CardType = strType; // encode.GetString(certType).Replace("\0", "").Trim();
                    info.UID = encode.GetString(Uid).Replace("\0", "").Trim();
                }
                else
                {
                    info.IdCardName = encode.GetString(name).Replace("\0", "").Trim();
                    info.CNName = encode.GetString(cnName).Replace("\0", "").Trim();
                    info.Sex = encode.GetString(sex).Replace("\0", "").Trim();
                    info.Nation = encode.GetString(peopleNation).Replace("\0", "").Trim();
                    info.NationCode = encode.GetString(peopleNationCode).Replace("\0", "").Trim();
                    info.Birthday = encode.GetString(birthday).Replace("\0", "").Trim();
                    info.IdCardCode = encode.GetString(number).Replace("\0", "").Trim();
                    info.Department = encode.GetString(signdate).Replace("\0", "").Trim();
                    info.Validate = encode.GetString(validtermOfStart).Replace("\0", "").Trim();
                    info.ExpiryDate = encode.GetString(validtermOfEnd).Replace("\0", "").Trim();
                    info.CardType = strType;
                    info.UID = encode.GetString(Uid).Replace("\0", "").Trim();
                }
                Log.WriteAsync($"读卡成功:{info.IdCardName}-{info.IdCardCode}-{info.Department}-{info.Validate}-{info.ExpiryDate}");
                return info;
            }
            catch (Exception ex)
            {
                _error = $"读取卡详细信息发生了异常: {ex.Message}.";
                Log.WriteExceptionAsync(ex.ToString());
                return null;
            }
        }

        private string GetTime(string dateTime, string format)
        {
            try
            {
                string s = dateTime;
                if (dateTime.Length == 8)
                {
                    string[] strArray = new string[] { dateTime.Substring(0, 4), "-", dateTime.Substring(4, 2), "-", dateTime.Substring(6, 2) };
                    s = string.Concat(strArray);
                }
                return DateTime.Parse(s).ToString(format);
            }
            catch (Exception)
            {
                return "";
            }
        }

        public void SavePort()
        {
            _option.SerialPortNum = _port;
            _option.Save();
        }

        private void LoadConfig()
        {
            if (!File.Exists(_option.ConfigFilePath))
            {
                _option.Save();
            }
            _option.Load();
            Log.WriteAsync(_option.ToString());
            this.TimeoutMillisecond = _option.TimeoutSecond * 1000;
            string dllDir = System.Environment.GetEnvironmentVariable("TMP") + "\\chinaidcard";   //GetAssemblyDirectory();
            // 照片保存在当前目录
            ZPPath = $"{dllDir}\\zp.bmp"; 
            FPPath = $"{dllDir}\\wz.txt";
        }

        /// <summary>
        /// 执行单次读取身份证操作
        /// </summary>
        /// <returns></returns>
        public bool Read(string inParams, out string outParams)
        {
            outParams = "";
            _error = "";
            if (!_bInited)
            {
                _error = "阅读器未初始化.";
                return false;
            }
            bool readSuccess = false;
            _error = "";
            try
            {
                IdCardInfo cardInfo = null;
                readSuccess = ReadCard(out cardInfo);
                if (readSuccess)
                {
                    outParams = ConvertToJsonString(cardInfo);
                }  
                else
                {
                    outParams = ErrorMessage;
                }
                return readSuccess;
            }
            catch (Exception ex)
            {
                _error = string.Format("读取身份证信息发生了异常.\n异常详情:{0}", ex.ToString());
                Log.WriteExceptionAsync(_error);
                return false;
            }
        }

        private string ConvertToJsonString(IdCardInfo cardInfo)
        {
            //$"姓名:{info.IdCardName}," +
            //        $"性别:{info.Sex}," +
            //        $"出生日期{info.Birthday}," +
            //        $"签发机关:{info.Department}," +
            //        $"身份证号:{info.IdCardCode}," +
            //        $"民族:{info.Nation}," +
            //        $"起始日期:{info.Validate}," +
            //        $"有效期限:{info.ExpiryDate}, " +
            //        $"头像路径:{info.Photo}");

            IDCardAll idCard = new IDCardAll();
            idCard.number = cardInfo.IdCardCode;
            idCard.address = cardInfo.Address;
            idCard.birthday = cardInfo.Birthday;
            idCard.name = cardInfo.IdCardName;

            idCard.people = cardInfo.Nation;
            idCard.sex = cardInfo.Sex;
            idCard.signdate = cardInfo.Department;
            idCard.validtermOfStart = cardInfo.Validate;
            idCard.validtermOfEnd = cardInfo.ExpiryDate;
            idCard.HeadImage = cardInfo.Photo;
            return JsonConvert.SerializeObject(idCard);
        }

        private string GetCardInfoString(ref IdCardInfo cardInfo)
        {
            JObject outParam = new JObject();
            outParam.Add("ZJHM", cardInfo.IdCardCode);
            outParam.Add("XM", cardInfo.IdCardName);
            outParam.Add("XB", cardInfo.Sex);
            outParam.Add("MZ", cardInfo.Nation);
            outParam.Add("DZ", cardInfo.Address);
            outParam.Add("CSRQ", cardInfo.Birthday);
            outParam.Add("QFDW", cardInfo.Department);        
            outParam.Add("QFSJ", cardInfo.IssueDate);
            outParam.Add("SXSJ", cardInfo.ExpiryDate);
            outParam.Add("ZP", cardInfo.Photo);
            return outParam.ToString();
        }

        public override void Init(string inParam, out string outParam)
        {
            outParam = "";
            if (_bInited)
            {
                return;
            }
            if (Open(_option.SerialPortNum, _option.Baudrate))
            {
                _bInited = true;
                return;
            }
            if(Init())
            {
                _bInited = true;
                return;
            }
            else
            {
                outParam = _error;
            }
        }

        public override bool DoAction(string param, out string outParam)
        {
            return Read(param, out outParam);
        }

        public override void Start(string param, out string outParam)
        {
            outParam = null;
            poll = new Polling(Read, param);
            poll.TimeoutMilliSecond = TimeoutMillisecond;
            poll.ScanInterval = _option.ScanInterval;
            poll.DoFailed += this.OnDoFailed;
            poll.Timeout += this.OnDoTimeout;
            poll.Start(OnWorkingCompleted);
        }

        public override void Stop(string param, out string outParam)
        {
            outParam = null;
            if (poll != null)
            {
                poll.Stop();
                poll.Dispose();
                poll = null;
            }
        }

        public override void Exit(string inParams, out string outParam)
        {
            outParam = "";
            try
            {
                Close();
                DeleteTempData();
            }
            catch (Exception ex)
            {
                Log.WriteExceptionAsync(ex.ToString());
            }
            finally
            {
                _bInited = false;
            }
        }

        /// <summary>
        /// 清理身份证头像相片
        /// </summary>
        public void DeleteTempData()
        {
            try
            {
                if (File.Exists(ZPPath))
                {
                    File.Delete(ZPPath);
                }
            }
            catch (Exception ex)
            {
                string strLog = string.Format($"删除{ZPPath}发生了异常: {0}", ex.ToString());
                Log.WriteExceptionAsync(strLog);
            }
            try
            {
                if (File.Exists(FPPath))
                {
                    File.Delete(FPPath);
                }
            }
            catch (Exception ex)
            {
                string strLog = string.Format($"删除{FPPath}发生了异常: {0}", ex.ToString());
                Log.WriteExceptionAsync(strLog);
            }
        }

        public override void ShowConfigDialog(string inParam)
        {
            FormSetting form = new FormSetting();
            form.ShowDialog();
        }
    }
}

